home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / videbjct / necdrivr.c < prev    next >
Encoding:
Text File  |  1993-06-15  |  40.3 KB  |  1,284 lines

  1. /*
  2.  * Copyright (c) 1990, 1991, 1992 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23.  
  24. /* $Header: /Source/Media/collab/VideoObject/RCS/NECDriver.c,v 0.32 93/02/07 13:02:29 drapeau Exp $ */
  25. /* $Log:    NECDriver.c,v $
  26.  * Revision 0.32  93/02/07  13:02:29  drapeau
  27.  * Changed method in which driver waits for outstanding return codes.  The
  28.  * driver now tries to take into account multiple NEC drivers being called from
  29.  * the same application.  The old scheme did not work when doing dubbing operations
  30.  * where two NEC's were involved.
  31.  * This scheme has not been completely tested, and some errors may remain.
  32.  * 
  33.  * Revision 0.31  92/10/01  14:26:13  drapeau
  34.  * Fixed minor errors in NECSendCode() and NECReadOK() to improve response of
  35.  * the NEC PC-VCR driver.
  36.  * In NECSendCode(), added a test to check if the "CL" interrupt command was
  37.  * sent, in addition to testing for the "CV" interrupt command being sent.
  38.  * Also, added a diagnostic message to make debugging of the driver simpler.
  39.  * In NECReadOK(), added code to consume leftover completion codes.  This occurs
  40.  * when a PlayFromTo() is sent with a non-blocking status (which tells
  41.  * NECSendCode() not to wait for the completion message).  If the NECStop()
  42.  * function is called before the PlayFromTo completes, the Stop command
  43.  * tells the deck to disregard any outstanding commands, in effect removing the
  44.  * completion code from the NEC's output buffer.  If, however, the PlayFromTo
  45.  * manages to complete before the Stop function is called (or any function, for
  46.  * that matter), the NEC will be left with a completion code waiting to be
  47.  * consumed; it appears that even the "CV" and "CL" interrupt commands will not
  48.  * wipe this completion code out of the NEC's output buffer.
  49.  * So, NECReadOK() checks for this latter case, where an outstanding completion
  50.  * code is read from the buffer when in fact the "command acknowledged" code was
  51.  * expected.
  52.  * 
  53.  * Revision 0.30  92/09/29  18:13:32  drapeau
  54.  * Made several improvements to the driver and fixed a few errors.
  55.  * The improvements have to do with improving the response time of the NEC when
  56.  * performing the NECPlayFromTo() function.  Before the improvements were made,
  57.  * PlayFromTo() always blocked until the playback was completed.  Now, the
  58.  * playback begins and the function returns immediately, returning control to
  59.  * the calling application.  If a stop or pause message are sent before playback
  60.  * is complete, the playback will quickly be interrupted by the new driver.
  61.  * In addition, fixed an error in NECSendCode(): the function was checking the
  62.  * string "command" to see if the command being sent was an interrupt command;
  63.  * instead, NECSendCode() should have been checking the incoming "code" string
  64.  * passed in as argument.
  65.  * 
  66.  * Revision 0.29  92/09/28  12:39:09  drapeau
  67.  * PlayFromTo() was modified to reflect the new semantics of the VideoObject
  68.  * library.
  69.  * 
  70.  * Revision 0.28  92/09/08  14:39:07  drapeau
  71.  * Made several changes to account for limitations of the NEC PC-VCR.  The code
  72.  * to handle these limitations used to be in the vcrEdit application, but it
  73.  * is more appropriate to handle the NEC-specific limitations here.
  74.  * Specifically, the NEC PC-VCR cannot access the 1st 3 seconds of timecoded
  75.  * tape, so searches to any address less than 3 seconds are now caught as
  76.  * invalid in the NECSearch() function.
  77.  * Also, the NEC cannot play a segment of video less than 3 seconds long, so
  78.  * the PlayFromTo() function now catches this error and accommodates for the
  79.  * problem by temporarily adjusting the endpoint of the video segment so that
  80.  * the edit will last 3 seconds.  It is still up to the author to modify the
  81.  * edit length in the application's edit list (or whereever the edit length
  82.  * is stored).
  83.  * 
  84.  * Revision 0.27  92/09/01  17:04:52  drapeau
  85.  * Fixed errors in calls to NECSetAudio(); it was being called with an extra
  86.  * parameter; this was caught as a result of adding function prototypes to
  87.  * all related files, for better ANSI compliance.
  88.  * Fixed definition of NECSetAddressingMode() to comply with definition of
  89.  * the generic VideoObject.
  90.  * Added methods NECRecord() and NECRecordFromTo() in accordance with new
  91.  * VideoObject methods.
  92.  * 
  93.  * Revision 0.26  92/08/05  16:15:34  drapeau
  94.  * Made several improvements to the CalcSpeed and PlayAtSpeedDir functions,
  95.  * so they don't call the NEC too often.  Since communications with the
  96.  * NEC is slow, it is always to the advantage of the driver to avoid
  97.  * sending commands and queries to the NEC.  The new functions keep
  98.  * some internal state about the NEC playback mode, in order to avoid
  99.  * constant queries to the NEC.
  100.  * Also, minor cosmetic changes to some diagnostic-printing calls.
  101.  * 
  102.  * Revision 0.25  92/07/30  15:24:27  drapeau
  103.  * Several changes:
  104.  * * Renamed "VcrInsert()" and "VcrPlayTo()" to "NECInsert()" and
  105.  *   "NECPlayTo()".
  106.  * * Removed all XView-specific code, to increase the portability of the driver.
  107.  * * Re-formatted all function declarations to conform to ANSI function
  108.  *   prototype standards.
  109.  * * Replaced hard-coded references to 30 frame-per-second frame rates with
  110.  *   new definition "FrameRate".  All math is based on this definition now,
  111.  *   allowing the driver to be used in places where the frame rate is not
  112.  *   30 fps.
  113.  * * Improved diagnostic messages.  Diagnostics now report the serial port
  114.  *   being used for the command when possible.
  115.  * 
  116.  * Revision 0.24  92/06/16  23:45:33  drapeau
  117.  * Changed the way asynchronous calls are handled, to avoid using XView-specific
  118.  * code.  This might need to be changed one more time, when the new
  119.  * toolkit-independent asynchronous I/O scheme is implemented for all
  120.  * appropriate drivers (including this one).
  121.  * 
  122.  * Revision 0.23  92/01/03  16:49:33  drapeau
  123.  * Changed occurrances of "NULL" in calls to Browse() to use "0" instead.
  124.  * This is due to the ANSI definition of NULL as "(void*)0".
  125.  * 
  126.  * Revision 0.22  91/09/30  17:04:40  lim
  127.  * Implemented NECPing.
  128.  * 
  129.  * Revision 0.21  91/08/28  14:10:29  lim
  130.  * Changed use of Error to PlayerReturnError
  131.  * 
  132.  * Revision 0.20  91/08/27  17:47:55  lim
  133.  * Corrected calls to DisplayError(). Now there is a second
  134.  * argument as well.
  135.  * 
  136.  * Revision 0.19  91/08/24  17:49:43  lim
  137.  * Implemented PrintDiagnostics.
  138.  * 
  139.  * Revision 0.18  91/08/24  13:37:13  lim
  140.  * 1. Updated to use status codes in new PlayerStatus.h
  141.  * 2. Clear Marker() removed as part of video object.
  142.  * 
  143.  * Revision 0.17  91/08/20  16:28:27  lim
  144.  * Parameters for SetVideo : 0 - Video mute
  145.  *                  1 - Video on
  146.  * 
  147.  * Revision 0.16  91/08/20  10:05:51  lim
  148.  * A blocking segment play function is added which is used by the dubbing
  149.  * application.
  150.  * 
  151.  * Revision 0.15  91/08/17  20:36:56  lim
  152.  * 1. Stop and Pause implemented with interrupt capability.
  153.  * 2. Clear Marker implemented to do as specs in videoObj.h require.
  154.  * 3. Audio fixed so that segment play reflects user's audio setting.
  155.  * 4. Fixed QueryAudio and QueryVideo.
  156.  * 
  157.  * Revision 0.14  91/08/15  12:51:13  lim
  158.  * Changed interrupt command to use "CV" which clears buffer and is able to interrupt any command 
  159.  * currently being executed.
  160.  * 
  161.  * Revision 0.13  91/08/12  13:14:17  lim
  162.  * Removed Quit() call from CheckTape.
  163.  * 
  164.  * Revision 0.12  91/08/08  16:17:44  lim
  165.  * 1. Removed references to vcrEdit app, so as to be able to incorporate
  166.  *    into library.
  167.  * 2. Added instance pointer, 'theObject' to all public calls.
  168.  * 3. Added SetAddressingMode, which sets 'addMode' to 1 for indexing and
  169.  *    0 for normal.
  170.  * 4. Removed DisplaySpeed. Now PlayAtSpeedDir() uses framesPerSecond to 
  171.  *    judge how to change speed.
  172.  * 5. Added NECClient and now PlayFromTo() uses notify_set_input_func rather
  173.  *    than timers.
  174.  * 6. ReadHeader() has second parameter, 'result' which allows result of
  175.  *    query to be passed back to the calling function even if it is not an
  176.  *    integer.
  177.  * 
  178.  * Revision 0.11  91/07/20  11:38:22  lim
  179.  * Changed NECPlayFromTo to fit function 
  180.  * prototype. The speed field does nothing in actuality, because
  181.  * the NEC is unable to play edits at speeds other than 30 f/s.
  182.  * NULL for startFrame in NECPlayFromTo now means resume play
  183.  * and do not set counter. This used to be represented by -1.
  184.  * Added NECCalcSpeed. Always returns 30.
  185.  * All floats are changed to doubles.
  186.  * 
  187.  * Revision 0.10  91/07/16  16:10:49  lim
  188.  * Initial revision.
  189.  *  */
  190.  
  191. #include "NECDriver.h"
  192.  
  193. static char vcrrcsid[] = "$Header: /Source/Media/collab/VideoObject/RCS/NECDriver.c,v 0.32 93/02/07 13:02:29 drapeau Exp $";
  194.  
  195. int addMode;                                /* Addressing mode : 1 = Index, 0 = Normal */
  196. int audioMuted;                                /* Whether audio has been muted or not for segment play.
  197.                                        QueryAudio is unable to detect this condition. */
  198. int waitConsumeAO[2] = {0, 0};                        /* Set to 1 when we do not wait to consume the AO after
  199.                                        issuing a command. */
  200. static char diagMsg[128];
  201.  
  202.  
  203. /*  Support routines.  These implement the VCR functions  */
  204.  
  205.  
  206. /* Check status of player. */
  207. int
  208.   NECQueryStatus(VideoObject* theObject)
  209. {
  210.   NECSendCode(theObject, "DS", 1);         
  211.   return(NECReadResponse(theObject, "DS"));
  212. }                                    /* end function NECQueryStatus */
  213.  
  214.  
  215. /* Checks if a tape has been inserted into the deck.
  216.  * If no tape, display message and checks again.
  217.  * If the user does not want to insert a tape, the program quits.
  218.  */
  219. void
  220.   NECCheckTape(VideoObject* theObject)
  221. {
  222.   int result;
  223.   int choice;
  224.   
  225.   result = NECQueryStatus(theObject);
  226.   if (result == PlayerNoMedium)
  227.   {           
  228.     choice = DisplayChoice("Please insert a tape into the player.","",
  229.                "OK", "No");
  230.     if (choice) 
  231.       NECCheckTape(theObject);
  232.     else 
  233.       return;
  234.   }
  235. }                                    /* end function NECCheckTape */
  236.  
  237.  
  238. /* Initializes the NEC to default settings */
  239. int
  240.   NECSetDefaults(VideoObject*    theObject,
  241.          int        audio,
  242.          int        addMode,                /* unused */
  243.          int        addDisplay,                /* unused */
  244.          int        addDisplayMode)                /* unused */
  245. {
  246.   NECPower(theObject, FeatureOn);                    /* Turn on player */
  247.   NECStop(theObject);
  248.   NECSetVideo(theObject, FeatureOn);
  249.   NECScreenSelect(theObject, Green, BrightnessNormal);
  250.   NECClearScreen(theObject);
  251.   NECSetAudio(theObject, audio);
  252.   NECCheckTape(theObject);                        /* Checks if tape has been inserted */
  253.   return(PlayerOk);
  254. }                                    /* end function NECSetDefaults */
  255.  
  256.  
  257.  
  258. /* Convert address passed in (in terms of # of frames) into format used by player */
  259. void
  260.   NECConvertAdd(int* start,
  261.         int* startFrame,
  262.         int* end,
  263.         int* endFrame,
  264.         int  startAdd,
  265.         int  endAdd)
  266. {
  267.   if (startAdd < 0)
  268.     startAdd = -startAdd;
  269.   
  270.   *start = startAdd / FrameRate;
  271.   *startFrame = startAdd % FrameRate;
  272.   
  273.   *end = endAdd / FrameRate;
  274.   *endFrame = endAdd % FrameRate;
  275.   return;
  276. }                                    /* end function NECConvertAdd */
  277.  
  278.  
  279. /* Functions to send and read commands from NEC */
  280.  
  281. /* Sends vcr code.
  282.  * Reads CP or error message.
  283.  * Checks if we are waiting for a status. If so, we return to calling function.
  284.  * Otherwise, we read AO or error message.
  285.  */
  286. int
  287.   NECSendCode(VideoObject*    theObject,
  288.           char*        code,
  289.           int        waitStatus)
  290. {
  291.   char    command[15];
  292.   int    w;
  293.   int    result;
  294.   int    whichPlayer = 0;
  295.   
  296.   if (strcmp(theObject->DevConfig->serialPort, "/dev/ttya") == 0)   /* Determine which serial port is being used for... */
  297.     whichPlayer = 0;                            /* ...this command */
  298.   else
  299.     whichPlayer = 1;
  300.   
  301.   if (waitConsumeAO[whichPlayer] != 0)                    /* Is the driver waiting to consume a completion code? */
  302.   {                                    /* Yes (this flag set only by the PlayFromTo method) */
  303.     sprintf(diagMsg, "%s :\twaitConsumeAO flag was set; reading AO.\n",
  304.         theObject->DevConfig->serialPort,
  305.         w, code);
  306.     PrintDiagnostics(diagMsg);
  307.     if ((strcmp(code, "CV") != 0) && (strcmp(code, "CL") != 0))        /* Is the incoming command an interrupt? */
  308.       NECReadOK(theObject, "AO", "SP");                    /* No, normal command: read completion from last command */
  309.     waitConsumeAO[whichPlayer] = 0;
  310.   }
  311.   strcpy(command,code);
  312.   strcat(command,"\r");
  313.   w = write(theObject->DevConfig->fd,command,strlen(command));
  314.   sprintf(diagMsg, "%s :\tWrote %d bytes, code is ::%s::\n",
  315.       theObject->DevConfig->serialPort,
  316.       w, code);
  317.   PrintDiagnostics(diagMsg);
  318.  
  319.   result = NECReadOK(theObject, "CP",code);  
  320.   if (result == PlayerReturnError)
  321.     return result;
  322.   
  323.   if (waitStatus == 0)                            /* Should the function wait for an "AO"? */
  324.     return (NECReadOK(theObject, "AO" , code));                /* Yes, block until it or an error condition is returned */
  325.   else                                    /* No, return immediately */
  326.     return PlayerOk;
  327. }                                    /* end function NECSendCode */
  328.  
  329.  
  330. /* Reads ack codes (CP or AO) from NEC.
  331.  * If error, display error message.
  332.  */
  333. int
  334.   NECReadOK(VideoObject*    theObject,
  335.         char*        okCode,
  336.         char*        currCom)
  337. {
  338.   int  i;
  339.   int  returnCode;
  340.   char response[15];
  341.   
  342.   if ((i = read(theObject->DevConfig->fd, response, 15)) > 0) 
  343.   {
  344.     response[i-1] = '\0';
  345.     
  346.     sprintf(diagMsg, "%s :\tRead %d bytes, response is ::%s::\n",
  347.         theObject->DevConfig->serialPort,
  348.         i, response);         
  349.     PrintDiagnostics(diagMsg);
  350.     
  351.     if (strncmp(response, "EE", 2) == 0) 
  352.     {
  353.       sscanf(&response[2],"%d",&returnCode);
  354.       NECErrorDecode(theObject, returnCode, currCom);
  355.       return PlayerReturnError;
  356.     } 
  357.     else if (strncmp(response, okCode, 2) == 0) 
  358.       return PlayerOk;
  359.     else if ((strncmp(okCode, "CP", 2) == 0) &&                /* Check if the driver is expecting a "command accepted"... */
  360.       (strncmp(response, "AO", 2) == 0))                /* ...code but the NEC returned a "command completed";... */
  361.     {                                    /* ...This indicates that the last command's completion... */
  362.       NECReadOK(theObject, okCode, currCom);                /* ...was not consumed until now.  So, now that it is... */
  363.     }                                    /* ...consumed, the current "command accepted" code can... */
  364.   }                                    /* ... be consumed. */
  365.   else
  366.     return PlayerReturnError;
  367. }                                    /* end function NECReadOK */
  368.  
  369.  
  370.  
  371. /* Returns response (status or information) from NEC.
  372.  * If error, display error message.
  373.  */
  374. int
  375.   NECReadResponse(VideoObject*    theObject,
  376.           char*        currCom)
  377. {
  378.   int  i;
  379.   int  returnCode;
  380.   char response[15];
  381.   
  382.   if ((i = read(theObject->DevConfig->fd, response, 15)) > 0) 
  383.   {
  384.     response[i-1] = '\0';
  385.     
  386.     sprintf(diagMsg, "%s :\tRead %d bytes, response is ::%s::\n",
  387.         theObject->DevConfig->serialPort,
  388.         i, response);         
  389.     PrintDiagnostics(diagMsg);
  390.     if (strncmp(response, "EE", 2) == 0)                /* Error message */
  391.     {
  392.       sscanf(&response[2],"%d",&returnCode);
  393.       NECErrorDecode(theObject, returnCode, currCom);
  394.       return (PlayerReturnError);
  395.     } 
  396.     else if (strncmp(response, "SS", 2) == 0)                /* Status return */
  397.     {
  398.       sscanf(&response[2],"%d",&returnCode);
  399.       switch (returnCode)
  400.       {
  401.        case 0:
  402.     returnCode = PlayerNoMedium;
  403.     break;
  404.        case 1:
  405.     returnCode = PlayerStop;
  406.     break;
  407.        case 2:
  408.     returnCode = PlayerRecording;
  409.     break;
  410.        case 3:
  411.     returnCode = PlayerRecordPause;
  412.     break;
  413.        case 4:
  414.     returnCode = PlayerForwardFast;
  415.     break;
  416.        case 5:
  417.     returnCode = NECHiSpeedSearch;
  418.     break;
  419.        case 6:
  420.     returnCode = NECPictureSearch;
  421.     break;
  422.        case 7:
  423.     returnCode = PlayerForwardPlay;
  424.     break;
  425.        case 9:
  426.     returnCode = PlayerPause;
  427.     break;
  428.        case 10:
  429.     returnCode = NECRPictureSearch;
  430.     break;
  431.        case 11:
  432.     returnCode = NECRHiSpeedSearch;
  433.     break;
  434.        case 12:
  435.     returnCode = PlayerReverseFast;
  436.     break;
  437.        case 13:
  438.     returnCode = NECForwardIndexScanSearch;
  439.     break;
  440.        case 14:
  441.     returnCode = NECIndexScan;
  442.     break;
  443.        case 15:
  444.     returnCode = NECReverseIndexScanSearch;
  445.     break;
  446.        case 16:
  447.     returnCode = NECSlow1_30;
  448.     break;
  449.        case 17:
  450.     returnCode = NECSlow1_10;
  451.     break;
  452.        case 18:
  453.     returnCode = NECSlow1_5;
  454.     break;
  455.        case 19:
  456.     returnCode = NECInsertPause;
  457.     break;
  458.        case 20:
  459.     returnCode = NECInsertPlay;
  460.     break;
  461.        case 21:
  462.     returnCode = NECAudioDubPause;
  463.     break;
  464.        case 22:
  465.     returnCode = NECAudioDubPlay;
  466.     break;
  467.        case 23:
  468.     returnCode = NECAudioInsertPause;
  469.     break;
  470.        case 24:
  471.     returnCode = NECAudioInsertPlay;
  472.     break;
  473.        default:
  474.     returnCode = PlayerUnknownReturnCode;
  475.       }
  476.     }
  477.     else if (strncmp(response, "PG", 2) == 0)                /* Tape address */
  478.       sscanf(&response[2],"%d",&returnCode);
  479.     else if (strncmp(response, "PY", 2) == 0)                /* Video signal info */
  480.       returnCode = PlayerVideoSignalPresent;
  481.     else if (strncmp(response, "PN", 2) == 0)                
  482.       returnCode = PlayerVideoSignalAbsent;
  483.     else if (strncmp(response, "MONO", 4) == 0)                /* Status returns that are not integers */
  484.       returnCode = PlayerAudioMono;
  485.     else if (strncmp(response, "STEREO", 6) == 0)
  486.       returnCode = PlayerAudioStereo;
  487.     else if (strncmp(response, "LINE-IN", 7) == 0)
  488.       returnCode = PlayerLineInput;
  489.     else if (strncmp(response, "TV-IN", 5) == 0)
  490.       returnCode = PlayerTunerInput;
  491.     else if (strncmp(response, "L-OUT", 5) == 0)
  492.       returnCode = PlayerAudioLeft;
  493.     else if (strncmp(response, "R-OUT", 5) == 0)
  494.       returnCode = PlayerAudioRight;
  495.     else if (strncmp(response, "RL-OUT", 6) == 0)
  496.       returnCode = PlayerAudioStereo;
  497.     else if (strncmp(response, "NORMAL", 6) == 0)
  498.       returnCode = PlayerAudioStereo;
  499.     else if (strncmp(response, "PICTURE", 7) == 0)
  500.       returnCode = PlayerVideoSignalPresent;
  501.     else if (strncmp(response, "NO-PICTURE", 10) == 0)
  502.       returnCode = PlayerVideoSignalAbsent;
  503.     else if (strncmp(response, "STANDARD", 8) == 0)
  504.       returnCode = PlayerSPMode;
  505.     else if (strncmp(response, "EXTENDED", 8) == 0)
  506.       returnCode = PlayerEPMode;
  507.     
  508.     NECReadOK(theObject, "AO", currCom);                /* Except for error messages, all other ...
  509.                                        ... responses have AO ack sent at the end. */
  510.     return (returnCode);
  511.     
  512.   }
  513. }                                    /* end function NECReadResponse */
  514.  
  515.  
  516.  
  517. /*  Player functions  */
  518.  
  519.  
  520. /* Reads tape header.
  521.  * If no tape, display message and tries to read header again.
  522.  * If the user does not want to insert a tape, the program quits.
  523.  * Otherwise, stores tape header info into currTape and resets counter.
  524.  */
  525. int
  526.   NECReadHeader(VideoObject*    theObject,
  527.         char*        header)
  528. {
  529.   char response[15];
  530.   int result;
  531.   int i;
  532.   
  533.   NECCheckTape(theObject);                        /* Checks that a tape exists */
  534.   
  535.   NECSendCode(theObject, "HR", 1);
  536.   if ((i = read(theObject->DevConfig->fd, response, 15)) > 0) 
  537.   {
  538.     response[i-1] = '\0';
  539.     
  540.     sprintf(diagMsg, "%s :\tRead %d bytes, response is ::%s::\n",
  541.         theObject->DevConfig->serialPort,
  542.         i, response);         
  543.     PrintDiagnostics(diagMsg);
  544.     if (strncmp(response, "EE", 2) == 0)                /* Error message */
  545.     {
  546.       sscanf(&response[2],"%d",&result);
  547.       NECErrorDecode(theObject, result, "HR");
  548.       return PlayerReturnError;
  549.     } 
  550.     else if (strncmp(response, "HG", 2) == 0)                
  551.       strncpy(header, &response[2], 4);    
  552.   }
  553.   NECReadOK(theObject, "AO", "HG");    
  554.   NECSendCode(theObject, "CR", 0);                    /* Counter reset */
  555.   return PlayerOk;
  556.   
  557. }                                    /* end function NECReadHeader */
  558.  
  559.  
  560. int
  561.   NECStop(VideoObject* theObject)
  562. {
  563.   NECSendCode(theObject, "CV", 0);                    /* Clears all commands */
  564.   NECSendCode(theObject, "CL", 0);                    /* Clears command buffer */
  565.   return (NECSendCode(theObject, "ST", 0));
  566. }                                    /* end function NECStop */
  567.  
  568.  
  569. /* Ejects the tape.
  570.  * First checks if it is ok to eject the tape. We cannot do it while recording.
  571.  * If it is recording, we display error message.
  572.  * If not, we eject and try to read header of new tape. 
  573.  */
  574. int
  575.   NECEject(VideoObject* theObject)
  576. {
  577.   int result;
  578.   
  579.   result = NECQueryStatus(theObject);
  580.   
  581.   if ((result == PlayerRecording) ||                    /* Not valid when in recording */
  582.       (result == PlayerRecordPause))
  583.   {
  584.     DisplayError("Eject cannot be executed when recording", " ");
  585.     return PlayerReturnError;
  586.   }
  587.   else 
  588.   {
  589.     NECSendCode(theObject, "EJ", 0);
  590.     NECCheckTape(theObject);
  591.     return PlayerOk;
  592.   }
  593. }                                    /* end function NECEject */
  594.  
  595.  
  596. /* Pauses the tape.
  597.  * First checks if it is ok to pause the tape. We can only do it while in record/playback.
  598.  * If neither, we display error message.
  599.  */
  600. int
  601.   NECStill(VideoObject* theObject)
  602. {
  603.   int result;
  604.   
  605.   NECSendCode(theObject, "CV", 0);                    /* Clears all commands */
  606.   result = NECQueryStatus(theObject);
  607.   
  608.   switch (result) 
  609.   {
  610.    case PlayerForwardPlay:
  611.    case PlayerPause:
  612.    case PlayerRecording:
  613.    case PlayerRecordPause:
  614.     return (NECSendCode(theObject, "PS",0));
  615.    default:
  616.     NECSendCode(theObject, "PL", 0);
  617.     return (NECSendCode(theObject, "PS",0));
  618.   }
  619.   
  620. }                                    /* end function NECStill */
  621.  
  622.  
  623. int
  624.   NECPlay(VideoObject* theObject)
  625. {
  626.   return (NECSendCode(theObject, "PL",0));
  627. }                                    /* end function NECPlay */
  628.  
  629.  
  630.  
  631. /* Search to address.
  632.  * Mutes video and audio before search, and resets it after search.
  633.  */
  634. void
  635.   NECSearch(VideoObject*    theObject,
  636.         int            address,
  637.         int            frame)
  638. {
  639.   int    searchAddress = 0;
  640.   char command[10];
  641.   
  642.   searchAddress = (address * FrameRate) + frame;            /* Calculate the requested search address */
  643.   if (searchAddress < (3 * FrameRate))                    /* Was the requested address illegal? (the NEC cannot... */
  644.   {                                    /* ...search to a position before 3 seconds into the... */
  645.     DisplayError("The NEC PC-VCR cannot access the 1st 3 seconds",  /* ...coded portion of the tape)  If so, print an error... */
  646.          "of its tape.  Please try somewhere later in the tape."); /* ...and return without doing the search. */
  647.     return;
  648.   }
  649.   
  650.   NECSendCode(theObject, "VM1", 0);                    /* Mute video and audio before searching */
  651.   NECSendCode(theObject, "AM1", 0);
  652.   
  653.   sprintf(command, "JP%d:%d", address, frame);                
  654.   NECSendCode(theObject, command, 0);                        
  655.   
  656.   NECSendCode(theObject, "VM0", 0);                    /* Reset video and audio after searching */
  657.   NECSendCode(theObject, "AM0", 0);
  658.   return;
  659. }                                    /* end function NECSearch */
  660.  
  661.  
  662. /* Plays a segment of video.
  663.  * Searches to start address if we don't want to start from current position.
  664.  * Plays to end address.
  665.  * A timer is set to receive the AO ack after correct amount of time, so as...
  666.  * ... not to hold up the application.
  667.  */
  668. int
  669.   NECPlayFromTo(VideoObject*    theObject,
  670.         int        startAdd,
  671.         int        endAdd,
  672.         int        speedInFrames)                /* Not used, NEC is unable to play edits ... */
  673. {                                    /* ... at speeds other than 1x speed */
  674.   char command[10];
  675.   int from;
  676.   int fromFrame;
  677.   int to;
  678.   int toFrame;
  679.   int initialAudioSetting;
  680.   int    whichPlayer = 0;
  681.   
  682.   if (strcmp(theObject->DevConfig->serialPort, "/dev/ttya") == 0)   /* Determine which serial port is being used for... */
  683.     whichPlayer = 0;                            /* ...this command */
  684.   else
  685.     whichPlayer = 1;
  686.   
  687.   if (addMode)                                /* Is address mode index mode? */
  688.   {
  689.     addMode = 0;                            /* Yes, set address mode to frame mode */
  690.     return (NECSearchIndex(theObject, startAdd, endAdd));
  691.   }
  692.   
  693.   if ((startAdd != 0) && (endAdd != 0) && (startAdd != endAdd) &&   /* If edit is a "play from start to end" edit, then... */
  694.       ((endAdd - startAdd) < (3 * FrameRate)))                /* ...is the requested edit less than 3 seconds long? */
  695.   {                                    /* Yes, report the error and adjust so something is played */
  696.     DisplayError("The NEC PC-VCR cannot play edits less than 3 seconds.",
  697.          "Please make necessary adjustments in the future.");
  698.     endAdd = (startAdd + (3 * FrameRate));                /* Make the requested segment 3 seconds long */
  699.   }
  700.   
  701.   NECConvertAdd(&from, &fromFrame, 
  702.         &to, &toFrame, startAdd, endAdd);
  703.   if (startAdd == endAdd)                        /* Case a: Search to start address and still */
  704.   {
  705.     NECSearch(theObject, from, fromFrame);
  706.     return(PlayerOk);                            /* NECSearch should really return a status value,... */
  707.   }                                    /* ...but it doesn't, so this function will return something */
  708.   
  709.   if ((startAdd > 0) && (endAdd == 0))                    /* Case b: Search to start addr. and still (blocking search) */
  710.   {                                    /* Search to start address without losing audio setting. */
  711.     initialAudioSetting = NECQueryAudio(theObject);            /* Query current audio setting */
  712.     NECSearch(theObject, from, fromFrame);                /* Do the search */
  713.     if (!audioMuted)                            /* Restore Audio if necessary */
  714.     {
  715.       switch (initialAudioSetting)
  716.       {
  717.        case PlayerAudioLeft:
  718.     NECSetAudio(theObject, 1);
  719.     break;
  720.        case PlayerAudioRight:
  721.     NECSetAudio(theObject, 2);
  722.     break;
  723.        case PlayerAudioStereo:
  724.     NECSetAudio(theObject, 3);
  725.     break;
  726.       }
  727.     }
  728.     return(PlayerOk);
  729.   }
  730.   
  731.   if ((startAdd == 0) && (endAdd > 0))                    /* Case c: play from current position (no search) until... */
  732.   {                                    /* ...endAdd is reached, at speed "speedInFrames" */
  733.     sprintf(command, "SP%d:%d", to, toFrame);                /* Play to end address. */
  734.     NECSendCode(theObject, command, 1);                    /* Send the command but do not block waiting for completion */
  735.     waitConsumeAO[whichPlayer] = 1;                    /* Set flag telling NECSendCode to wait for completion... */
  736.     if (audioMuted)                            /* ...of this command the next time it is called */
  737.       audioMuted = 0;
  738.   }
  739.   if ((startAdd != 0) && (endAdd != 0) && (startAdd < endAdd))        /* Case d: play from startAdd to endAdd in... */
  740.   {                                    /* ...speed "speedInFrames" */
  741.     NECSearch(theObject, from, fromFrame);                /* Search to start address */
  742.     sprintf(command, "SP%d:%d", to, toFrame);                /* Play to end address. */
  743.     NECSendCode(theObject, command, 1);
  744.     if (audioMuted)
  745.       audioMuted = 0;
  746.   }    
  747.   return PlayerOk;
  748. }                                    /* end function NECPlayFromTo */
  749.  
  750.  
  751.  
  752. int
  753.   NECStep(VideoObject*        theObject,
  754.       enum Direction    direction)
  755. {
  756.   int result;
  757.   
  758.   if (direction == Reverse)                        /* Reverse step is not available with the NEC */
  759.     return PlayerOk;
  760.   
  761.   result = NECQueryStatus(theObject);
  762.   
  763.   if (result == PlayerPause)                        /* Valid only when in playback pause */
  764.   {
  765.     return (NECSendCode(theObject, "FS", 0));
  766.   }
  767.   else         
  768.   {
  769.     DisplayError("Player must be in playback pause mode first", " ");
  770.     return PlayerReturnError;
  771.   }  
  772. }                                    /* end function NECStep */
  773.  
  774.  
  775. int
  776.   NECFastForward(VideoObject* theObject)
  777. {
  778.   int mode;
  779.   int result;
  780.   char command[3];
  781.   
  782.   if (addMode)                                /* Addressing mode is index */
  783.   {
  784.     addMode = 0;
  785.     return (NECScanIndex(theObject, Forward));
  786.   }
  787.   
  788.   result = NECQueryStatus(theObject);
  789.   
  790.   if ((result == PlayerForwardPlay) || (result == PlayerPause))        /* If in playback mode, we scan forward */
  791.     mode = 1;
  792.   else if ((result != PlayerRecording) && 
  793.        (result != PlayerRecordPause))                /* Otherwise, we fast forward - Not valid if recording */
  794.     mode = 0;  
  795.   else
  796.     DisplayError("Fast forward not valid when recording", " ");
  797.   
  798.   sprintf(command, "FF%d", mode);
  799.   return (NECSendCode(theObject, command, 0));
  800.   
  801. }                                    /* end function NECFastForward */
  802.  
  803.  
  804. int
  805.   NECReverse(VideoObject* theObject)
  806. {
  807.   int mode;
  808.   char command[3];
  809.   int result;
  810.   
  811.   if (addMode)                                /* Addressing mode is index */
  812.   {
  813.     addMode = 0;
  814.     return (NECScanIndex(theObject, Reverse));
  815.   }
  816.   
  817.   result = NECQueryStatus(theObject);  
  818.   
  819.   if ((result == PlayerForwardPlay) || (result == PlayerPause))        /* If in playback mode, we scan back */
  820.     mode = 1;
  821.   else if ((result != PlayerRecording) &&
  822.        (result != PlayerRecordPause))                /* Otherwise, we rewind - Not valid if recording */
  823.     mode = 0;
  824.   else 
  825.   {
  826.     DisplayError("Reverse not valid when recording", " ");
  827.     return (PlayerReturnError);
  828.   }
  829.   
  830.   sprintf(command, "RW%d", mode);
  831.   return (NECSendCode(theObject, command, 0));
  832. }                                    /* end function NECReverse */
  833.  
  834.  
  835. int
  836.   NECScanIndex(VideoObject*    theObject,
  837.            enum Direction    dir)
  838. {
  839.   int result;
  840.   result = NECQueryStatus(theObject);
  841.   addMode = 0;
  842.   
  843.   if (result != PlayerStop)                        /* NEC must be in stop mode. */
  844.     NECStop(theObject);
  845.   
  846.   NECSendCode(theObject, "IC", 0);
  847.   if (dir == Forward)
  848.     return (NECSendCode(theObject, "FF0", 0));
  849.   else
  850.     return (NECSendCode(theObject, "RW0", 0));
  851.   
  852. }                                    /* end function NECScanIndex */
  853.  
  854.  
  855. int
  856.   NECSearchIndex(VideoObject*    theObject,
  857.          int        num,
  858.          int        dir)
  859. {
  860.   char command[4];
  861.   int status;
  862.   
  863.   status = NECQueryStatus(theObject);
  864.   
  865.   if (status != PlayerStop)
  866.     NECStop(theObject);
  867.   
  868.   sprintf(command, "IS%d", num);
  869.   NECSendCode(theObject, command, 0);
  870.   if (dir)
  871.     return (NECSendCode(theObject, "RW0", 0));
  872.   else
  873.     return (NECSendCode(theObject, "FF0", 0));
  874.   
  875. }                                    /* end function NECSearchIndex */
  876.  
  877. int
  878.   NECWait(VideoObject*    theObject,
  879.       char*        status)
  880. {
  881.   char command[15];
  882.   
  883.   sprintf(command, "WN:%s", status);
  884.   return (NECSendCode(theObject, command, 0));
  885. }                                    /* end function NECWait */
  886.  
  887.  
  888. int
  889.   NECPower(VideoObject*    theObject,
  890.        int        mode)
  891. {
  892.   if (mode == FeatureOn)
  893.     return (NECSendCode(theObject, "PW1", 0));
  894.   else if (mode == FeatureOff)
  895.     return (NECSendCode(theObject, "PW0", 0));
  896.   else                                    /* Toggles */
  897.     return (NECSendCode(theObject, "PW", 0));
  898. }                                    /* end function NECPower */
  899.  
  900.  
  901. int
  902.   NECSetAddressingMode(VideoObject* theObject, int mode)
  903. {
  904.   addMode = mode;
  905. }                                    /* end function NECSetAddressingMode */
  906.  
  907.  
  908. int
  909.   NECSetAudio(VideoObject*    theObject,
  910.           int        mode)
  911. {
  912.   if (mode)
  913.     NECSendCode(theObject, "AM0", 0);
  914.   
  915.   switch (mode) 
  916.   {
  917.    case 0:
  918.     audioMuted = 1;
  919.     return (NECSendCode(theObject, "AM1", 0));
  920.    case 1:
  921.     return (NECSendCode(theObject, "RLL", 0));
  922.    case 2:
  923.     return (NECSendCode(theObject, "RLR", 0));
  924.    case 3:
  925.     return (NECSendCode(theObject, "RLS", 0));
  926.    case 4:
  927.     return (NECSendCode(theObject, "RLN", 0));
  928.   }
  929.   
  930. }                                    /* end function NECSetAudio */
  931.  
  932. int
  933.   NECSetVideo(VideoObject*    theObject,
  934.           int        mode)
  935. {
  936.   if (mode == FeatureOn)                        /* On */
  937.     return (NECSendCode(theObject, "VM0", 0));                
  938.   else                                    /* Off */
  939.     return (NECSendCode(theObject, "VM1", 0));                
  940. }                                    /* end function NECSetVideo */
  941.  
  942.  
  943. int 
  944.   NECQueryVideo(VideoObject* theObject)
  945. {
  946.   NECSendCode(theObject, "PT", 1);
  947.   return (NECReadResponse(theObject, "PT"));
  948. }                                    /* end function NECQueryVideo */
  949.  
  950.  
  951.  
  952. int
  953.   NECQueryAudio(VideoObject* theObject)
  954. {
  955.   NECSendCode(theObject, "DS5", 1);
  956.   return (NECReadResponse(theObject, "DS5"));
  957. }                                    /* end function NECQueryAudio */
  958.  
  959.  
  960. int
  961.   NECScreenSelect(VideoObject*    theObject,
  962.           int        color,
  963.           int        brightness)
  964. {
  965.   char code[6];
  966.   
  967.   sprintf(code, "MB%d:%d", color, brightness);
  968.   return (NECSendCode(theObject, code, 0));
  969. }                                    /* end function NECScreenSelect */
  970.  
  971.  
  972.  
  973. /* Returns tape address in frames, NOT SECONDS.
  974.  * Valid only when in playback mode.
  975.  */
  976. int
  977.   NECQueryFrame(VideoObject* theObject)
  978. {
  979.   int address;
  980.   int result;
  981.   
  982.   result = NECQueryStatus(theObject);
  983.   
  984.   if (result == PlayerForwardPlay) 
  985.   {
  986.     NECSendCode(theObject, "RP", 1);
  987.     address =  FrameRate * NECReadResponse(theObject, "RP");        /* Put in terms of frames */
  988.     return (address);    
  989.   }
  990.   else
  991.   {
  992.     DisplayError("Player must be in playback mode first", " ");
  993.     return PlayerReturnError;
  994.   }
  995. }                                    /* end function NECQueryFrame */
  996.  
  997.  
  998. int
  999.   NECClearScreen(VideoObject* theObject)
  1000. {
  1001.   return (NECSendCode(theObject, "ELA",0));
  1002. }                                    /* end function NECClearScreen */
  1003.  
  1004.  
  1005.  
  1006. /* This function returns all speeds in terms of 30 frame-per-second
  1007.  * devices, even though the internal calculations are done in
  1008.  * rate-independent units. 
  1009.  */
  1010.  
  1011. int
  1012.   NECCalcSpeed(VideoObject*    theObject,
  1013.            int        framesInEdit,
  1014.            int        playMode)
  1015. {
  1016.   if (framesInEdit > FrameRate * 2)                    /* Don't go into high speed unless requested frame... */
  1017.   {                                    /* ...rate is greater than 2x speed (arbitrary heuristic) */
  1018.     if (framesInEdit <= (5 * FrameRate))
  1019.       framesInEdit = 150;                        /* 5x speed (for SP mode) */
  1020.     else if (framesInEdit <= (9 * FrameRate))
  1021.       framesInEdit = 270;                        /* 9x speed (for SP mode, fastest speed available) */
  1022.   }
  1023.   else                                    
  1024.     if (framesInEdit < (FrameRate / 10))
  1025.       framesInEdit = 1;                            /* 1/30th speed */
  1026.     else if (framesInEdit < (FrameRate / 5))
  1027.       framesInEdit = 3;                            /* 1/10th speed */
  1028.     else if (framesInEdit < FrameRate)
  1029.       framesInEdit = 6;                            /* 1/5th speed */
  1030.     else
  1031.       framesInEdit = 30;                        /* 1x speed */
  1032.   
  1033.   return framesInEdit;                            
  1034. }                                    /* end function NECCalcSpeed */
  1035.  
  1036.  
  1037.  
  1038. int
  1039.   NECPlayAtSpeedDir(VideoObject*    theObject,
  1040.             int            framesPerSecond,
  1041.             enum Direction    direction)
  1042. {
  1043.   int        speed;
  1044.   static int    status = PlayerForwardPlay;
  1045.   static int    lastSpeed = 0;
  1046.   
  1047.   if ((status == PlayerRecording) || (status == PlayerRecordPause)) /* Error checks */
  1048.   {
  1049.     DisplayError("Player cannot change speed when recording", " ");
  1050.     return PlayerReturnError;
  1051.   }
  1052.   else if (status == PlayerStop)
  1053.   {
  1054.     DisplayError("Player cannot change speed when in stop mode", " ");
  1055.     return PlayerReturnError;
  1056.   }
  1057.   speed = NECCalcSpeed(theObject, framesPerSecond, 0);
  1058.   if (speed == lastSpeed)                        /* Was a different speed requested? */
  1059.     return (PlayerOk);                            /* No, don't bother sending a new command to the player */
  1060.   
  1061.   lastSpeed = speed;                            /* Update new speed requested */
  1062.   switch (speed)
  1063.   {
  1064.    case 1:                                /* 1/30th speed */
  1065.     if (direction == Forward)                        /* NEC PC-VCR doesn't allow reverse playback at slow speeds */
  1066.     {
  1067.       switch (status)                            /* Do the right thing according to player's current speed */
  1068.       {
  1069.        case PlayerPause:                        /* Paused, increase speed one notch */
  1070.     NECSendCode(theObject, "SL+", 0);
  1071.     break;
  1072.        case NECSlow1_30:                        /* Already at requested speed; do nothing */
  1073.     break;
  1074.        case NECSlow1_10:                        /* Go into next slower speed */
  1075.     NECSendCode(theObject, "SL-", 0);
  1076.     break;
  1077.        case NECSlow1_5:                            /* Slow speed two notches */
  1078.     NECSendCode(theObject, "SL-", 0);               
  1079.     NECSendCode(theObject, "SL-", 0);
  1080.     break;
  1081.        case NECPictureSearch:            
  1082.        case NECRPictureSearch:
  1083.        case NECHiSpeedSearch:        
  1084.        case NECRHiSpeedSearch:
  1085.     NECSendCode(theObject, "PL", 0);                /* Put into play mode first */
  1086.        case PlayerForwardPlay:
  1087.     NECSendCode(theObject, "SL-", 0);
  1088.     NECSendCode(theObject, "SL-", 0);
  1089.     NECSendCode(theObject, "SL-", 0);
  1090.     break;
  1091.       }                                    /* end switch (status) */
  1092.       status = NECSlow1_30;
  1093.     }                                    /* end if (direction... */
  1094.     break;                                /* end 1/30th speed */
  1095.    case 3:                                /* 1/10th speed */
  1096.     if (direction == Forward)                        /* NEC PC-VCR doesn't allow reverse playback at slow speeds */
  1097.     {
  1098.       switch (status)                            /* Do the right thing according to player's current speed */
  1099.       {
  1100.        case PlayerPause:                        /* Paused, increase speed two notches */
  1101.     NECSendCode(theObject, "SL+", 0);
  1102.     NECSendCode(theObject, "SL+", 0);
  1103.     break;
  1104.        case NECSlow1_30:                        /* Increase speed one notch */
  1105.     NECSendCode(theObject, "SL+", 0);
  1106.     break;
  1107.        case NECSlow1_10:                        /* Already at requested speed; do nothing */
  1108.     break;
  1109.        case NECSlow1_5:                            /* Slow speed one notch */
  1110.     NECSendCode(theObject, "SL-", 0);
  1111.     break;
  1112.        case NECPictureSearch:            
  1113.        case NECRPictureSearch:
  1114.        case NECHiSpeedSearch:        
  1115.        case NECRHiSpeedSearch:
  1116.     NECSendCode(theObject, "PL", 0);                /* Put into play mode first */
  1117.        case PlayerForwardPlay:
  1118.     NECSendCode(theObject, "SL-", 0);
  1119.     NECSendCode(theObject, "SL-", 0);
  1120.     break;
  1121.       }                                    /* end switch (status) */
  1122.       status = NECSlow1_10;
  1123.     }                                    /* end if (direction... */
  1124.     break;
  1125.    case 6:                                /* 1/5th speed */
  1126.     if (direction == Forward)                        /* NEC PC-VCR doesn't allow reverse playback at slow speeds */
  1127.     {
  1128.       switch (status)                            /* Do the right thing according to player's current speed */
  1129.       {
  1130.        case PlayerPause:                        /* Paused, increase speed three notches */
  1131.     NECSendCode(theObject, "SL+", 0);
  1132.     NECSendCode(theObject, "SL+", 0);
  1133.     NECSendCode(theObject, "SL+", 0);
  1134.     break;
  1135.        case NECSlow1_30:                        /* Increase speed two notches */
  1136.     NECSendCode(theObject, "SL+", 0);
  1137.     NECSendCode(theObject, "SL+", 0);
  1138.     break;
  1139.        case NECSlow1_10:                        /* Go into next higher speed */
  1140.     NECSendCode(theObject, "SL+", 0);
  1141.     break;
  1142.        case NECSlow1_5:                            /* Already at requested speed; do nothing */
  1143.     break;
  1144.        case NECPictureSearch:            
  1145.        case NECRPictureSearch:
  1146.        case NECHiSpeedSearch:        
  1147.        case NECRHiSpeedSearch:
  1148.     NECSendCode(theObject, "PL", 0);                /* Put into play mode first */
  1149.        case PlayerForwardPlay:
  1150.     NECSendCode(theObject, "SL-", 0);
  1151.     break;
  1152.       }                                    /* end switch (status) */
  1153.       status = NECSlow1_5;
  1154.     }                                    /* end if (direction... */
  1155.     break;
  1156.    case 30:                                /* 1x speed */
  1157.     if (direction == Forward)                        /* NEC PC-VCR doesn't support reverse play at normal speed */
  1158.     {
  1159.       NECSendCode(theObject, "PL", 0);
  1160.       status = PlayerForwardPlay;
  1161.     }
  1162.     break;
  1163.    case 150:                                /* Fast speed (5x SP mode, 9x EP mode) */
  1164.     if (direction == Forward)
  1165.     {
  1166.       NECSendCode(theObject, "FF1", 0);
  1167.       status = NECPictureSearch;
  1168.     }
  1169.     else
  1170.     {
  1171.       NECSendCode(theObject, "RW1", 0);
  1172.       status = NECRPictureSearch;
  1173.     }
  1174.     break;
  1175.    case 270:                                /* Jet speed (9x SP mode, 21x EP mode) */
  1176.     if (direction == Forward)
  1177.     {
  1178.       NECSendCode(theObject, "FF2", 0);
  1179.       status = NECHiSpeedSearch;
  1180.     }
  1181.     else
  1182.     {
  1183.       NECSendCode(theObject, "RW2", 0);
  1184.       status = NECRHiSpeedSearch;
  1185.     }
  1186.     break;
  1187.   }                                    /* end switch (speed) */
  1188.   return PlayerOk;
  1189. }                                    /* end function NECPlayAtSpeedDir */
  1190.  
  1191.  
  1192. int NECRecord(VideoObject* theObject)
  1193. {
  1194.   return(NECSendCode(theObject, "RC", 0));
  1195. }                                    /* end function NECRecord */
  1196.  
  1197.  
  1198. int NECRecordFromTo(VideoObject*    theObject,
  1199.             int            startAddress,
  1200.             int            endAddress,
  1201.             int            speed)
  1202. {
  1203.   int    end;
  1204.   int    endFrame;
  1205.   char    command[10];
  1206.  
  1207.   if ((startAddress == 0) && (endAddress == 0))                /* Enter insert edit mode */
  1208.     return(NECSendCode(theObject, "PI", 0));
  1209.   else if ((startAddress == 0) && (endAddress > 0))            /* Record from present address until end address is reached */
  1210.   {
  1211.     end = endAddress / FrameRate;
  1212.     endFrame = endAddress % FrameRate;
  1213.     sprintf(command, "SP%d:%d", end, endFrame);
  1214.     return(NECSendCode(theObject, command, 0));
  1215.   }
  1216. }                                    /* end function NECRecordFromTo */
  1217.  
  1218.  
  1219. int 
  1220.   NECPing(VideoObject* theObject)
  1221. {
  1222.   int nr;
  1223.   char response[1];
  1224.   
  1225.   write(theObject->DevConfig->fd, "PW1\r", 4);                /* Power on command */
  1226.   sprintf(diagMsg, "%s :\tSent ping.\n",
  1227.       theObject->DevConfig->serialPort);
  1228.   PrintDiagnostics(diagMsg);
  1229.   nr = read(theObject->DevConfig->fd, response, 1);            /* Read CP */
  1230.   if (nr)
  1231.   {
  1232.     sprintf(diagMsg, "%s :\tSuccessful ping.\n",
  1233.         theObject->DevConfig->serialPort);
  1234.     PrintDiagnostics(diagMsg);
  1235.     read(theObject->DevConfig->fd, response, 1);            /* Read AO */
  1236.   }
  1237.   else
  1238.   {
  1239.     sprintf(diagMsg,"%s :\tPing unsuccessful.\n",
  1240.         theObject->DevConfig->serialPort);
  1241.     PrintDiagnostics(diagMsg);
  1242.   }
  1243.   return nr;
  1244. }                                    /* end function NECPing */
  1245.  
  1246.  
  1247. void
  1248.   NECErrorDecode(VideoObject*    theObject,
  1249.          int        ecode,
  1250.          char*        string)
  1251. {
  1252.   char errMsg[50];
  1253.   
  1254.   switch (ecode) 
  1255.   {
  1256.    case ErrPowerOff :
  1257.      strcpy(errMsg, "Please turn the VCR power on");
  1258.      break;
  1259.     case ErrCantReadAdd :
  1260.       strcpy(errMsg, "Tape address cannot be read");
  1261.      break;
  1262.     case ErrNoCassette:
  1263.      strcpy(errMsg, "Please insert a cassette into VCR first");
  1264.      break;
  1265.     case ErrIncorrectCommand :
  1266.       strcpy(errMsg, "Incorrect command");
  1267.      break;
  1268.     case ErrIncorrectParameter :
  1269.       strcpy(errMsg, "Incorrect parameter(s) or no parameters needed");
  1270.      break;
  1271.     case ErrReceptionBuffOverflow :
  1272.       strcpy(errMsg, "Warning : there are too many commands in the buffer");
  1273.      break;
  1274.     case ErrCantReadHeader :
  1275.       strcpy(errMsg, "Header cannot be read");
  1276.      break;
  1277.     case ErrCantExecCommand :
  1278.       sprintf(errMsg, "%s cannot be executed. Please check VCR mode", string);
  1279.      break;
  1280.    }                                    /* end switch */
  1281.   DisplayError(errMsg, " ");
  1282.   return;
  1283. }                                    /* end function NECErrorDecode */
  1284.